package com.yy.QSManage.service.other.scheduler;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CalendarIntervalTriggerImpl;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;


@Service
@Slf4j
public class TaskSchedulerServiceImpl implements ITaskSchedulerService {


    @Resource
    private Scheduler scheduler;

    @Override
    @SneakyThrows
    public void save(TaskScheduler taskScheduler) {
        Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(taskScheduler.getJobClass());
        String jobName = taskScheduler.getJobName();
        String jobGroupName = StrUtil.isEmpty(taskScheduler.getJobGroupName()) ? Scheduler.DEFAULT_GROUP : taskScheduler.getJobGroupName();
        String triggerGroupName = StrUtil.isEmpty(taskScheduler.getJobGroupName()) ? Scheduler.DEFAULT_GROUP : taskScheduler.getJobGroupName();
        Date startTime = taskScheduler.getStartTime() == null ? new Date() : taskScheduler.getStartTime();
        Date endTime = taskScheduler.getEndTime();
        String description = StrUtil.isEmpty(taskScheduler.getDescription()) ? "" : taskScheduler.getDescription();

        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobName, jobGroupName)
                .withDescription(description)
                .storeDurably(taskScheduler.getIsDurable())
                .requestRecovery(taskScheduler.getRequestRecovery())
                .build();
        if (taskScheduler.getCronExpression() != null && taskScheduler.getCronExpression().length() > 0) {
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, triggerGroupName)
                    .startAt(startTime)
                    .endAt(endTime)
                    .withSchedule(CronScheduleBuilder.cronSchedule(taskScheduler.getCronExpression()).withMisfireHandlingInstructionFireAndProceed())
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
        } else {
            DateBuilder.IntervalUnit cycleUnit = DateBuilder.IntervalUnit.valueOf(taskScheduler.getIntervalUnit());
            Integer timeInterval = taskScheduler.getTimeInterval();
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, triggerGroupName)
                    .startAt(startTime)
                    .endAt(endTime)
                    .withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withInterval(timeInterval, cycleUnit).withMisfireHandlingInstructionFireAndProceed())
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
        }
    }

    /**
     * 移除定时任务--根据任务名称移除
     */
    @Override
    public void delete(String jobName) {
        delete(jobName, Scheduler.DEFAULT_GROUP);
    }

    /**
     * 移除定时任务
     */
    @Override
    @SneakyThrows
    public void delete(String jobName, String groupName) {
        groupName = StrUtil.isEmpty(groupName) ? Scheduler.DEFAULT_GROUP : groupName;

        JobKey jobKey = new JobKey(jobName, groupName);
        TriggerKey triggerKey = new TriggerKey(jobName, groupName);
        scheduler.pauseTrigger(triggerKey);
        scheduler.pauseJob(jobKey);
        // 移除触发器
        scheduler.unscheduleJob(triggerKey);
        // 删除任务
        scheduler.deleteJob(jobKey);

    }

    /**
     * 修改定时任务
     */
    @Override
    @SneakyThrows
    public void update(TaskScheduler taskScheduler) {
        delete(taskScheduler.getJobName());
        save(taskScheduler);
    }

    /**
     * 查询单个定时任务
     */
    @Override
    @SneakyThrows
    public TaskScheduler selectByName(String jobName, String groupName) {
        groupName = StrUtil.isEmpty(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
        TaskScheduler taskScheduler = new TaskScheduler();
        JobKey jobKey = new JobKey(jobName, groupName);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        taskScheduler.setJobName(jobName);
        taskScheduler.setJobGroupName(groupName);
        setJob(jobKey, taskScheduler, jobDetail);

        return taskScheduler;
    }

    /**
     * 查询单个定时任务
     */
    @Override
    public TaskScheduler selectByName(String jobName) {
        return selectByName(jobName, Scheduler.DEFAULT_GROUP);
    }

    /**
     * 查询定时任务列表
     */
    @Override
    @SneakyThrows
    public List<TaskScheduler> selectList(JobQuery jobQuery) {
        List<TaskScheduler> taskSchedulers = new ArrayList<>();
        GroupMatcher<JobKey> mathcher = GroupMatcher.anyJobGroup();
        String keyWord = jobQuery.getJobNameLike();
        Set<JobKey> jobKeys = scheduler.getJobKeys(mathcher);
        if (CollUtil.isEmpty(jobKeys)) {
            return new ArrayList<>();
        }
        for (JobKey jobKey : jobKeys) {
            if (StrUtil.isNotEmpty(keyWord) && !jobKey.getName().contains(keyWord)) {
                continue;
            }
            TaskScheduler taskScheduler = new TaskScheduler();
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            taskScheduler.setJobName(jobKey.getName());
            taskScheduler.setJobGroupName(jobKey.getGroup());
            List<? extends Trigger> triggers = setJob(jobKey, taskScheduler, jobDetail);
            taskScheduler.setState(scheduler.getTriggerState(triggers.get(0).getKey()).name());
            taskSchedulers.add(taskScheduler);
        }
        return taskSchedulers;
    }

    private List<? extends Trigger> setJob(JobKey jobKey, TaskScheduler taskScheduler, JobDetail jobDetail) throws SchedulerException {
        taskScheduler.setJobClass(jobDetail.getJobClass().getName());
        taskScheduler.setDescription(jobDetail.getDescription());
        List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
        Trigger trigger = triggers.get(0);
        taskScheduler.setStartTime(trigger.getStartTime());
        taskScheduler.setEndTime(trigger.getEndTime());
        if (trigger.getClass().equals(CronTriggerImpl.class)) {
            CronTriggerImpl cronTriggerImpl = (CronTriggerImpl) trigger;
            taskScheduler.setCronExpression(cronTriggerImpl.getCronExpression());
        }
        if (trigger.getClass().equals(CalendarIntervalTriggerImpl.class)) {
            CalendarIntervalTriggerImpl calendarIntervalTriggerImpl = (CalendarIntervalTriggerImpl) trigger;
            taskScheduler.setIntervalUnit(calendarIntervalTriggerImpl.getRepeatIntervalUnit().toString());
            taskScheduler.setTimeInterval(calendarIntervalTriggerImpl.getRepeatInterval());
        }
        return triggers;
    }

    /**
     * 暂停定时任务
     */
    @Override
    public void pause(String jobName) {
        pause(jobName, Scheduler.DEFAULT_GROUP);
    }

    /**
     * 暂停定时任务
     */
    @Override
    @SneakyThrows
    public void pause(String jobName, String groupName) {
        groupName = StrUtil.isEmpty(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
        TriggerKey triggerKey = new TriggerKey(jobName, groupName);
        scheduler.pauseTrigger(triggerKey);
        JobKey jobKey = new JobKey(jobName);
        scheduler.pauseJob(jobKey);

    }

    /**
     * 恢复定时任务
     */
    @Override
    public void resume(String jobName) {
        resume(jobName, Scheduler.DEFAULT_GROUP);
    }

    /**
     * 恢复定时任务
     */
    @Override
    @SneakyThrows
    public void resume(String jobName, String groupName) {
        groupName = StrUtil.isEmpty(groupName) ? Scheduler.DEFAULT_GROUP : groupName;

        TriggerKey triggerKey = new TriggerKey(jobName, groupName);
        scheduler.resumeTrigger(triggerKey);
        JobKey jobKey = new JobKey(jobName);
        scheduler.resumeJob(jobKey);

    }

    /**
     * 执行定时任务
     */
    @Override
    public void executeJob(String jobName) {
        executeJob(jobName, Scheduler.DEFAULT_GROUP);
    }

    /**
     * 执行定时任务
     */
    @Override
    @SneakyThrows
    public void executeJob(String jobName, String groupName) {
        groupName = StrUtil.isEmpty(groupName) ? Scheduler.DEFAULT_GROUP : groupName;
        JobKey jobKey = new JobKey(jobName, groupName);
        scheduler.triggerJob(jobKey);
    }
}
